#pragma once
#include <iostream>
#include <memory>
#include "Socket.hpp"
#include "Epoller.hpp"
#include <set>
using namespace NetWorkModule;
using namespace EpollerModule;

const int defaultport = 8888;
const int gblocklog = 32;
class EpollServer
{
    const static int gmaxevents = 64;

public:
    EpollServer(int port = defaultport) : _port(port),
                                          _listensock(new TcpSocket()),
                                          _epoller(new Epoller()),
                                          _isrunning(false)
    {
    }

    void InitServer()
    {
        // 1.创建listensock
        _listensock->BuildListensocketMethod(_port, gblocklog);
        lg.LogMessage(Info, "listensock create success, listensock is %d\n", _listensock->GetSockfd());

        // 2.创建epoll模型
        _epoller->InitEpoller();
        lg.LogMessage(Info, "init epoll success\n");

        // 3.将listensock添加到epoll中
        _epoller->AddEvents(_listensock->GetSockfd(), EPOLLIN);
        _set.insert(_listensock->GetSockfd());
    }

    bool Accpeter(std::string *clientip, uint16_t *clientport)
    {
        int sockfd = _listensock->AcceptConnection(clientip, clientport);
        if (sockfd < 0)
        {
            lg.LogMessage(Warning, "accept error\n");
            return false;
        }

        _epoller->AddEvents(sockfd, EPOLLIN); // 将接收的文件描述符交给epoll管理起来
        _set.insert(sockfd);
        return true;
    }

    int Recver(int sockfd, std::string *out)
    {
        // 每一个sockfd都要有一个输入和输出缓冲区！
        // 对fd进行封装
        char buffer[1024];
        ssize_t n = ::recv(sockfd, buffer, sizeof(buffer) - 1, 0); // bug???
        if (n > 0)
        {
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }

    void HandlerEvent(int n)
    {
        for (int i = 0; i < n; i++)
        {
            lg.LogMessage(Debug, "%d 个 events已经就绪了\n", n);
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if (events & EPOLLIN) // 是读事件就绪了
            {
                // 读事件就绪了分为   1.连接到来了 2.数据到来了
                if (sockfd == _listensock->GetSockfd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    if (!Accpeter(&clientip, &clientport))
                        continue;
                    lg.LogMessage(Info, "accept client success, client[%s:%d]\n", clientip.c_str(), clientport);
                }
                else // 数据到来了
                {
                    std::string message;
                    int n = Recver(sockfd, &message);
                    if (n > 0)
                    {
                        std::cout << "client say# " << message << std::endl;
                    }
                    else
                    {
                        if (n == 0)
                        {
                            lg.LogMessage(Info, "client %d close\n", sockfd);
                        }
                        else
                        {
                            lg.LogMessage(Error, "client recv %d error\n", sockfd);
                        }
                        _set.erase(sockfd);
                        _epoller->DelEvents(sockfd);
                        ::close(sockfd);
                    }
                }
            }
        }
    }

    void PrintDebug()
    {
        std::cout << "fd list: ";
        for (const auto &e : _set)
        {
            std::cout << e << " ";
        }
        std::cout << std::endl;
    }

    void Loop()
    {
        _isrunning = true;
        while (_isrunning)
        {
            PrintDebug();
            int timeout = -1;
            int n = _epoller->Wait(_revs, gmaxevents, timeout);
            switch (n)
            {
            case 0:
                lg.LogMessage(Debug, "timeout...\n"); // 数据还没有就绪
                break;
            case -1:
                lg.LogMessage(Error, "epoll wait failed!\n");
                break;
            default:
                lg.LogMessage(Info, "event happened\n");
                HandlerEvent(n); // 有几个已经就绪了
                break;
            }
        }
    }

    ~EpollServer()
    {
    }

private:
    int _port;
    std::unique_ptr<Socket> _listensock;
    std::unique_ptr<Epoller> _epoller;
    bool _isrunning;
    struct epoll_event _revs[gmaxevents];
    std::set<int> _set;
};
